package com.huiquan.analysis.job;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.huiquan.analysis.constants.AnalysisSentenceConstant;
import com.huiquan.analysis.dao.SentenceSnDao;
import com.huiquan.analysis.domain.SentenceSnDto;
import com.huiquan.framework.utils.MathUtil;

@Component
public class AnalysisSortJob {

	private static final Logger LOG = LoggerFactory.getLogger(AnalysisSortJob.class);

	@Autowired
	private SentenceSnDao sentenceSnDao;
	/*
	 * @Autowired private SentenceCache sentenceCache;
	 */

	/**
	 * 每天晚上执行，将主诉未标注句子排序
	 */
	public void sortZs() {
		LOG.info("Analysis sort job sort zhusu sentence begin");
		long startTime = System.currentTimeMillis();

		// 生成排序字段
		long start = System.currentTimeMillis();
		sentenceSnDao.initUnlabeledSn(AnalysisSentenceConstant.TYPE_ZS);
		LOG.info("Sort zs sentence job setSn2Database success,time=" + (System.currentTimeMillis() - start));

		// 计算每个句子的排序字段
		List<SentenceSnDto> snDtoList = getSnDto();

		// 将维护好的排序设置到数据库中
		start = System.currentTimeMillis();
		setSn2Database(snDtoList, AnalysisSentenceConstant.TYPE_ZS);
		// 将sid大于临界值的数据的排序值+1
		sentenceSnDao.updateSn2ValueBySid(18891718L);
		LOG.info("Sort zs sentence job setSn2Database success,time=" + (System.currentTimeMillis() - start));

		LOG.info("Analysis sort job sort zhusu sentence end,time=" + (System.currentTimeMillis() - startTime));
	}

	private void setSn2Database(List<SentenceSnDto> snDtoList, Integer type) {
		// 删除历史排序数据
		sentenceSnDao.deleteSn2ByType(type);

		// 添加数据到数据库
		List<Map<String, Object>> temp = new ArrayList<>();
		SentenceSnDto snDto;
		for (int i = 0; i < snDtoList.size(); i++) {
			if (i > 0 && i % 10000 == 0) {
				sentenceSnDao.batchInsertSn2(temp);
				temp.clear();
			}

			snDto = snDtoList.get(i);
			Map<String, Object> param = new HashMap<>();
			param.put("sid", snDto.getSid());
			param.put("sn", snDto.getSn());
			param.put("type", type);
			temp.add(param);
		}
		if (temp.size() > 0) {
			sentenceSnDao.batchInsertSn2(temp);
		}
	}

	private List<SentenceSnDto> getSnDto() {
		// 记录排序的map（频数例子：{1000,[3,2]}，表示频数为1000的句子有3个，排序为第2位），
		TreeMap<BigDecimal, List<Integer>> frequencySnMap = new TreeMap<>(); // 记录频数的排序
		TreeMap<BigDecimal, List<Integer>> vNumSnMap = new TreeMap<>(); // 记录分词个数排序
		TreeMap<BigDecimal, List<Integer>> vPercentSnMap = new TreeMap<>(); // 记录未标注分词百分比排序

		// 获取排序对应字段
		long startTime = System.currentTimeMillis();
		List<SentenceSnDto> snDtoList = getSortColumn(frequencySnMap, vNumSnMap, vPercentSnMap);
		LOG.info("Sort zs sentence job getSortColumn success,time=" + (System.currentTimeMillis() - startTime));

		// 排序后维护好实体
		startTime = System.currentTimeMillis();
		setSn(snDtoList, frequencySnMap, vNumSnMap, vPercentSnMap);
		LOG.info("Sort zs sentence job setSn success,time=" + (System.currentTimeMillis() - startTime));

		return snDtoList;
	}

	/**
	 * 计算每个参数的顺序，放入map的value中，维护参数实体中的顺序；计算三个参数顺序的调和平均值为最终顺序值
	 * 
	 * @param snDtoList
	 * @param frequencySnMap
	 * @param vNumSnMap
	 * @param vPercentSnMap
	 */
	private void setSn(List<SentenceSnDto> snDtoList, TreeMap<BigDecimal, List<Integer>> frequencySnMap,
			TreeMap<BigDecimal, List<Integer>> vNumSnMap, TreeMap<BigDecimal, List<Integer>> vPercentSnMap) {
		// 对频数进行排序
		setSn(frequencySnMap, true);

		// 对分词个数进行排序
		setSn(vNumSnMap, false);

		// 对分词百分比进行排序
		setSn(vPercentSnMap, true);

		Integer frequencySn, vNumSn, vPercentSn;
		BigDecimal v1, v2;
		Double sn;
		for (SentenceSnDto snDto : snDtoList) {
			frequencySn = frequencySnMap.get(snDto.getFrequency()).get(1);
			vNumSn = vNumSnMap.get(snDto.getVNum()).get(1);
			vPercentSn = vPercentSnMap.get(snDto.getVPercent()).get(1);

			snDto.setFrequencySn(frequencySn);
			snDto.setVNumSn(vNumSn);
			snDto.setVPercentSn(vPercentSn);

			v1 = MathUtil.mul(frequencySn.doubleValue(), vNumSn.doubleValue(), vPercentSn.doubleValue(), 3d);
			v2 = MathUtil.mul(frequencySn.doubleValue(), vNumSn.doubleValue())
					.add(MathUtil.mul(frequencySn.doubleValue(), vPercentSn.doubleValue()))
					.add(MathUtil.mul(vNumSn.doubleValue(), vPercentSn.doubleValue()));
			try {
				// 最终算出来的是三个排序占比的调和平均值
				sn = v1.divide(MathUtil.mul(v2.doubleValue(), (double) snDtoList.size()), 5, BigDecimal.ROUND_HALF_EVEN)
						.doubleValue();
				// sn值加入可信度的权
				sn = sn * 0.5 + (1 - snDto.getReliability()) * 0.5;
			} catch (Exception e) {
				e.printStackTrace();
				LOG.info("Sn calculate error!sid=" + snDto.getSid());
				continue;
			}
			snDto.setSn(sn);
		}
	}

	/**
	 * 根据排序维护map中的顺序值
	 * 
	 * @param snMap
	 * @param descend
	 *            是否倒序
	 */
	private void setSn(TreeMap<BigDecimal, List<Integer>> snMap, boolean descend) {
		Set<BigDecimal> keySet = snMap.keySet();
		if (descend) {
			keySet = snMap.descendingKeySet();
		}

		int count = 0;
		List<Integer> value;
		for (BigDecimal key : keySet) {
			value = snMap.get(key);
			value.add(count + (value.get(0) + 1) / 2);
			count += value.get(0);
		}
	}

	/**
	 * 将频数、个数、未标注占比三个数据放到TreeMap中，记录下每个值的个数，维护参数实体SentenceSnDto
	 * 
	 * @param frequencySnMap
	 * @param vNumSnMap
	 * @param vPercentSnMap
	 * @return
	 */
	private List<SentenceSnDto> getSortColumn(TreeMap<BigDecimal, List<Integer>> frequencySnMap,
			TreeMap<BigDecimal, List<Integer>> vNumSnMap, TreeMap<BigDecimal, List<Integer>> vPercentSnMap) {
		List<SentenceSnDto> snDtos = new ArrayList<>();

		List<Map<String, Object>> columns = sentenceSnDao.retriveSn1(AnalysisSentenceConstant.TYPE_ZS);
		BigDecimal frequency, vNum, vPercent;
		Long sid;
		double reliability = 0;
		for (Map<String, Object> column : columns) {
			sid = (long) column.get("sid");
			frequency = new BigDecimal(column.get("frequency").toString());
			vNum = new BigDecimal(column.get("v_num").toString());
			vPercent = (BigDecimal) column.get("v_percent");
			if (column.get("reliability") != null) {
				BigDecimal b = (BigDecimal) column.get("reliability");
				reliability = b.doubleValue();
			}

			setSnMap(frequencySnMap, frequency);
			setSnMap(vNumSnMap, vNum);
			setSnMap(vPercentSnMap, vPercent);

			SentenceSnDto snDto = new SentenceSnDto();
			snDto.setSid(sid);
			snDto.setFrequency(frequency);
			snDto.setVNum(vNum);
			snDto.setVPercent(vPercent);
			snDto.setReliability(reliability);

			snDtos.add(snDto);
		}

		return snDtos;
	}

	/**
	 * 计算每个key出现的次数，记录在map的value中
	 * 
	 * @param snMap
	 * @param v
	 */
	private void setSnMap(TreeMap<BigDecimal, List<Integer>> snMap, BigDecimal v) {
		List<Integer> sn;
		if ((sn = snMap.get(v)) != null) {
			sn.set(0, sn.get(0) + 1);
		} else {
			sn = new ArrayList<>();
			sn.add(1);
		}
		snMap.put(v, sn);

	}
}
